<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta http-equiv="Cache-Control" content="no-siteapp">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=1, minimum-scale=1, maximum-scale=1">
<meta name="referrer" content="never">
<meta name="robots" content="index,follow">
<link rel="shortcut icon" href="/favicon.png?v=198964">
<link rel="apple-itouch-icon" href="/favicon.png?v=198964">
<link href="/bundle/index.min.css" rel="stylesheet">
<link href="https://fonts.loli.net/css?family=Merriweather:300,700,700italic,300italic|Open+Sans:700,400" rel="stylesheet">
<link href="https://cdn.staticfile.org/prism/1.16.0/themes/prism.min.css" rel="stylesheet">
<link href="https://cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
<script>
    function ensureDate(e){return"object"!=typeof e&&(e=new Date(e)),e}function dateFormat(e,t){void 0===t&&(t=e,e=ensureDate());let n={M:(e=ensureDate(e)).getMonth()+1,d:e.getDate(),h:e.getHours(),m:e.getMinutes(),s:e.getSeconds(),q:Math.floor((e.getMonth()+3)/3),S:e.getMilliseconds()},r=new RegExp("([yMdhmsqS])+","g");return t=t.replace(r,function(t,r){let u=n[r];if(void 0!==u)return t.length>1&&(u=(u="0"+u).substring(u.length-2)),u;if("y"===r){return(e.getFullYear()+"").substring(4-t.length)}return t})}
</script>
    <meta name="keywords" content="Webpack 入门及实践,Webpack,">
    <meta name="description" content="Webpack 入门及实践,Webpack,">
    <meta name="author" content="江矿先森.">
    <title>Webpack 入门及实践</title>
    <link href="/bundle/iconfont.css" rel="stylesheet">
    <link href="/bundle/reward.css" rel="stylesheet">
    <script src='/bundle/av.min.js'></script>
    <script src='/bundle/valine.min.js'></script>
</head>

<body>
    <article class="container">
        <header class="header-wrap asset">
    <nav class="main-nav">
        <ul class="menu vertical naive">
            <li class="menu-item"><a href="/">Home</a></li>
            <li class="menu-item"><a href="/archive.html">Archive</a></li>
            <li class="menu-item"><a href="/tag.html">Tag</a></li>
            
            <li class="menu-item"><a href="/atom.xml">RSS</a></li>
        </ul>
    </nav>
    <div class="bgs" style="background-image: url(https://pic6.58cdn.com.cn/nowater/webim/big/n_v212fe49b1d6d5492cb1def84eeff4b142.jpg);"></div>
    <div class="vertical">
        <div class="header-wrap-content inner">
            <h3 class="title">Stay before every beautiful thoughts.</h3>
            <h3 class="subtitle">Just be nice, always think twice!</h3>
        </div>
    </div>
</header>
        <article class="main article">
            <h1 class="title">Webpack 入门及实践</h1>
            <section class="info">
                <span class="avatar" style="background-image: url(https://pic1.58cdn.com.cn/nowater/webim/big/n_v2a9773b605e754c8493cf53ca8f5c0d7e.jpg);"></span> <a class="name" href="javascript:;">江矿先森.</a> 
                <span class="date"><script>document.write(dateFormat( 1476069834 *1000, 'yyyy-MM-dd'))</script></span> 
                <span class="tags"><a class="tages" href="/tag/Webpack/index.html">Webpack</a></span>
            </section>
            <article class="content"><h1>webpack是什么？</h1>

<p>web开发中常用到的静态资源主要有JavaScript、CSS、图片、Jade等文件，webpack中将静态资源文件称之为模块。webpack是一个模块打包工具，其可以兼容多种js书写规范，且可以处理模块间的依赖关系，具有更强大的js模块化的功能。 官方网站中用下图清晰的描述了webpack采用不同的loader加载不同的资源文件，打包生成多个js文件，也可以根据设置生成独立的图片、css文件等。</p>

<h1>why webpack？</h1>

<p>在以往的开发过程中，经常会遇到以下三种情况：</p>

<ul>
<li>项目中资源多样性和依赖性 - js、css、png、less、jade等 为了方便开发，我们经常会使用不同的语法来编写文档，用less、sass、jade等会提高开发效率，但同时我们需要借助gulp或grunt来编写任务编译文件或对图片进行压缩等。</li>
<li>js模块规范复杂化 - AMD、CommonJS、UMD、ES6等 requireJS主要用来处理AMD规范的js文件，若使用CommonJS规范的js库文件，需进行AMD规范的封装，才能正常使用。而browserify主要处理CommonJS规范的文件，其他规范也需要进行转化。近期ES6的兴起，前面两种打包工具已经不能满足我们的需求了。</li>
<li>开发与线上文件不一致性（打包压缩造成影响）</li>
</ul>

<p>webpack可以很好地解决上面的问题，它具有Grunt、Gulp对于静态资源自动化构建的能力，是一个出色的前端自动化构建工具、模块化工具、资源管理工具。</p>

<h1>webpack 特性</h1>

<p>webpack具有requireJs和browserify的功能，但仍有很多自己的新特性：</p>

<ol>
<li>对 CommonJS 、 AMD 、ES6的语法做了兼容</li>
<li>对js、css、图片等资源文件都支持打包</li>
<li>串联式模块加载器以及插件机制，让其具有更好的灵活性和扩展性，例如提供对CoffeeScript、ES6的支持</li>
<li>有独立的配置文件webpack.config.js</li>
<li>可以将代码切割成不同的chunk，实现按需加载，降低了初始化时间</li>
<li>支持 SourceUrls 和 SourceMaps，易于调试</li>
<li>具有强大的Plugin接口，大多是内部插件，使用起来比较灵活</li>
<li>webpack 使用异步 IO 并具有多级缓存。这使得 webpack 很快且在增量编译上更加快</li>
</ol>

<h1>webpack 安装及使用</h1>

<p>webpack 可以作为全局的npm模块安装，也可以在当前项目中安装。</p>

<pre><code class="language-js">npm install -g webpack
</code></pre>

<pre><code class="language-js">npm install --save-dev webpack
</code></pre>

<p>webpack的使用通常有三种方式：</p>

<ul>
<li>命令行使用：webpack <entry.js> <result.js> 其中entry.js是入口文件，result.js是打包后的输出文件</li>
<li>node.js API使用：</li>
</ul>

<pre><code class="language-js">var webpack = require('webpack');
webpack({
//configuration
}, function(err, stats){});
</code></pre>

<p>默认使用当前目录的webpack.config.js作为配置文件。如果要指定另外的配置文件，可以执行：webpack &ndash;config webpack.custom.config.js</p>

<h1>webpack 常用命令</h1>

<p>webpack的使用和browserify有些类似，下面列举几个常用命令：</p>

<ul>
<li><code>webpack</code> 最基本的启动webpack命令</li>
<li><code>webpack -w</code> 提供watch方法，实时进行打包更新</li>
<li><code>webpack -p</code> 对打包后的文件进行压缩</li>
<li><code>webpack -d</code> 提供SourceMaps，方便调试</li>
<li><code>webpack --colors</code> 输出结果带彩色，比如：会用红色显示耗时较长的步骤</li>
<li><code>webpack --profile</code> 输出性能数据，可以看到每一步的耗时</li>
<li><code>webpack --display-modules</code> 默认情况下 node_modules 下的模块会被隐藏，加上这个参数可以显示这些被隐藏的模块
前面的四个命令比较基础，使用频率会比较大，后面的命令主要是用来定位打包时间较长的原因，方便改进配置文件，提高打包效率。</li>
</ul>

<h1>webpack 配置文件</h1>

<p>项目中静态资源文件较多，使用配置文件进行打包会方便很多。最简单的Webpack配置文件webpack.config.js如下所示：</p>

<pre><code class="language-js">module.exports = {
  entry:[
    './entry.js',
    ...
  ],
  output: {
    path: __dirname + '/output/',
    publicPath: &quot;/output/&quot;,
    filename: 'result.js'
  }
};
</code></pre>

<ul>
<li>其中entry参数定义了打包后的入口文件，数组中的所有文件会打包生成一个filename文件</li>
<li>output参数定义了输出文件的位置及名字，其中参数path是指文件的绝对路径，publicPath是指访问路径，filename是指输出的文件名。</li>
</ul>

<p>开发中需要将多个页面的公用模块独立打包，从而可以利用浏览器缓存机制来提高页面加载效率，减少页面初次加载时间，只有当某功能被用到时，才去动态的加载。这就需要使用webpack中的CommonsChunkPlugin插件。具体配置如下：</p>

<pre><code class="language-js">var CommonsChunkPlugin = require(&quot;webpack/lib/optimize/CommonsChunkPlugin&quot;);
module.exports = {
  entry: { a: &quot;./a&quot;, b: &quot;./b&quot; },
  output: { filename: &quot;[name].js&quot; },
  plugins: [ new CommonsChunkPlugin(&quot;common.js&quot;) ]
}
</code></pre>

<p>在文件中根据下面的方式引用即可。</p>

<pre><code class="language-html">&lt;script src=&quot;common.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;a.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;b.js&quot;&gt;&lt;/script&gt;
</code></pre>

<h1>webpack 模块加载器</h1>

<p>在webpack中JavaScript，CSS，LESS，TypeScript，JSX，CoffeeScript，图片等静态文件都是模块，不同模块的加载是通过模块加载器（webpack-loader）来统一管理的。loaders之间是可以串联的，一个加载器的输出可以作为下一个加载器的输入，最终返回到JavaScript上。loader的配置可以写在配置文件中，通过正则表达式的方式对文件进行匹配，具体可参见下面的示例：</p>

<pre><code class="language-js">module: {
    loaders: [{
        test: /\.less/,
        loader:  'style-loader!css-loader!less-loader'
    }, {
      test: /\.(png|jpg)$/,
      loader: 'url-loader?limit=10000&amp;name=build/[name].[ext]'
    }]
}
</code></pre>

<p>loader也支持在js文件中通过require的方式进行加载，只需要在require资源path的前面指定loader，用！来串联不同的loader和资源即可。</p>

<pre><code class="language-js">require(&quot;style!css!less!./mystyles.less&quot;);
</code></pre>

<h1>css文件独立打包</h1>

<p>在webpack中编写js文件时，可以通过require的方式引入其他的静态资源，可通过loader对文件自动解析并打包文件。通常会将js文件打包合并，css文件会在页面的header中嵌入style的方式载入页面。但开发过程中我们并不想将样式打在脚本中，最好可以独立生成css文件，以外链的形式加载。这时extract-text-webpack-plugin插件可以帮我们达到想要的效果。需要使用npm的方式加载插件，然后参见下面的配置，就可以将js中的css文件提取，并以指定的文件名来进行加载。</p>

<pre><code class="language-js">npm install extract-text-webpack-plugin –save-dev
</code></pre>

<pre><code class="language-js">plugins: [
    new ExtractTextPlugin('styles.css')
]
</code></pre>

<h1>图片打包</h1>

<p>webpack中对于图片的处理，可以通过url-loader来实现图片的压缩。</p>

<pre><code class="language-js">div.img{
    background: url(../image/xxx.jpg)
}

//或者
var img = document.createElement(&quot;img&quot;);
img.src = require(&quot;../image/xxx.jpg&quot;);
document.body.appendChild(img);
</code></pre>

<p>针对上面的两种使用方式，loader可以自动识别并处理。根据loader中的设置，webpack会将小于指点大小的文件转化成 base64 格式的 dataUrl，其他图片会做适当的压缩并存放在指定目录中。</p>

<pre><code class="language-js">module: {
    {
      test: /\.(png|jpg)$/,
      loader: 'url-loader?limit=10000&amp;name=build/[name].[ext]'
    }]
}
</code></pre>

<p>对于上面的配置，如果图片资源小于10kb就会转化成 base64 格式的 dataUrl，其他的图片会存放在build/文件夹下。</p>

<h1>webpack-dev-server</h1>

<p>webpack除了可以对模块进行打包，还提供了一个开发服务器。它的特点是：</p>

<ul>
<li>基于Node.js Express框架的轻量开发服务器</li>
<li>静态资源Web服务器</li>
<li>开发中会监听文件的变化在内存中实时打包</li>
</ul>

<p>webpack-dev-server需要单独安装，命令如下：</p>

<pre><code class="language-js">npm install -g webpack-dev-server
</code></pre>

<p>可以使用webpack-dev-server直接启动，也可以增加参数来获取更多的功能，具体配置可以参见<a href="http://webpack.github.io/docs/webpack-dev-server.html">官方文档</a>。默认启动端口8080，通过localhost:8080/webpack-dev-server/可以访问页面，文件修改后保存时会在页面头部看到sever的状态变化，并且会进行热替换，实现页面的自动刷新。</p>

<h1>双服务器模式</h1>

<p>项目开发中，仅有一台静态服务器是不能满足需求的，我们需要另启一台web服务器，且将静态服务器集成到web服务器中，就可以使用webpack的打包和加载功能。我们只需要修改一下配置文件就可以实现服务器的集成。</p>

<pre><code class="language-js"> entry: [
    './src/page/main.js',
    'webpack/hot/dev-server',
    'webpack-dev-server/client?http://127.0.0.1:8080'
  ]
  output: {
    path: __dirname,
    filename: '[name].js',
    publicPath: &quot;http://127.0.0.1:8080/assets/&quot;
  }
  plugins: [
    new webpack.HotModuleReplacementPlugin()
  ]
</code></pre>

<p>如果在开发中启动两个服务器并不是一个很好地选择，webpack提供了一个中间件webpack-dev-middleware，但其只能在生产环境中使用，可以实现在内存中实时打包生成虚拟文件，供浏览器访问以及调试。使用方式如下：</p>

<pre><code class="language-js">var webpackDevMiddleware = require(&quot;webpack-dev-middleware&quot;);
var webpack = require(&quot;webpack&quot;);

var compiler = webpack({
    // configuration
    output: { path: '/' }
});

app.use(webpackDevMiddleware(compiler, {
    // options
}));
</code></pre>

<h1>PS</h1>

<p>通过上面的介绍，基本涵盖了webpack的各个特性及简单的使用方法。最近出了个<code>hjs-webpack</code>，可以简化webpack中复杂的配置项，只需要安装开发中所需的loader，无需再module中配置，即可正确使用。有兴趣的同学可以尝试一下。</p>
</article>
            <section class="author">
                
                <div class="avatar" style="background-image: url(https://pic1.58cdn.com.cn/nowater/webim/big/n_v2a9773b605e754c8493cf53ca8f5c0d7e.jpg);"></div>
                <a class="name" href="javascript:;">江矿先森.</a>
                <div class="intro">前(台)端(菜), 喜欢瞎折腾新技术. 乜野都识少少, 先可以扮代表.</div>
            </section>
            <section class="social">
                <a href="https://github.com/joname1" target="_blank">
                    <i class="iconfont i-github"></i>
                </a>
                <a href="javascript:alert('你电脑中了不知名的病毒, 并抛出了警告 atob(“d3hJZDogam9uYW1lLmxpYW5ndGFu”)')" target="_blank">
                    <i class="iconfont i-wechat"></i>
                </a>
                <a href="https://www.zhihu.com/people/joname-liangtan" target="_blank">
                    <i class="iconfont i-zhihu"></i>
                </a>
                <a href="javascript:alert('对方不想跟你讲话, 并向你扔来一段乱码 atob(“am9uYW1lLmxpYW5ndGFuQGdtYWlsLmNvbQ”)')" target="_blank">
                    <i class="iconfont i-email"></i>
                </a>
            </section>

            <div class="reward">
                <div class="reward-button">赏
                    <span class="reward-code">
                        <span class="alipay-code">
                            <img class="alipay-img wdp-appear" src="https://pic1.58cdn.com.cn/nowater/webim/big/n_v24d5eae197a764eb194b61e366ff263ba.jpg"><b>支付宝扫码</b>
                        </span>
                    <span class="wechat-code">
                            <img class="wechat-img wdp-appear" src="https://pic1.58cdn.com.cn/nowater/webim/big/n_v20ec7ae162f6a4219b8d0b429a2dbc9b3.jpg"><b>微信扫码</b>
                        </span>
                    </span>
                </div>
                
                <p class="reward-notice">如果文章对你有帮助, 扫上方二维码请我喝杯奶茶吧 :p</p>
            </div>

            <div id="comment"></div>
            
        </article>
    </article>
    <footer class="footer clearfix">
    <span class="copyright">
        <script>
            document.write(new Date().getFullYear());
        </script> <i class="fa fa-copyright"></i> Made with <i class="fa fa-heart"></i> using &ltjoname /&gt
        <span id="runtime_span"></span>
    </span>
</footer>
    <script src="/bundle/index.min.js"></script>
    <script src="https://cdn.staticfile.org/prism/1.16.0/prism.min.js"></script>
    <script>
        new Valine({el: '#comment',appId: 'PieJ3iHvVTJ9C5yBudK6sxaT-MdYXbMMI',appKey: 'Yt25unM4vc9wzBvC2lL20Frc',placeholder: 'ヾﾉ≧∀≦)o来啊, 快活啊, 反正有大把时光!!',path: window.location.pathname,avatar: 'retro',pageSize: 10,guest_info: ['nick', 'mail'],lang: 'en'});
    </script>
</body>

</html>